package net.wanho.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import net.wanho.constant.CommonConstant;
import net.wanho.constant.UserConstant;
import net.wanho.mapper.RoleAuthMapper;
import net.wanho.po.AuthInfo;
import net.wanho.po.RoleAuth;
import net.wanho.service.AuthInfoService;
import net.wanho.mapper.AuthInfoMapper;
import net.wanho.util.CurrentUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
* @author Administrator
* @description 针对表【auth_info(权限表)】的数据库操作Service实现
* @createDate 2024-10-18 16:14:23
*/
@Service
@RequiredArgsConstructor
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public class AuthInfoServiceImpl extends ServiceImpl<AuthInfoMapper, AuthInfo>
    implements AuthInfoService{

    private final RedisTemplate<String,Object> redisTemplate;
    private final AuthInfoMapper authInfoMapper;
    private final RoleAuthMapper roleAuthMapper;

    @Override
    public List<AuthInfo> findMenus() {
        // 从redis中读取
        List<AuthInfo> menus = (List<AuthInfo>) redisTemplate.opsForValue().get(UserConstant.MENU_PREFIX + CurrentUtil.getUserId());
        if (!CollectionUtils.isEmpty(menus)){
            return menus;
        }

        /**
         * 获取当前用户的权限
         */
        List<AuthInfo> authInfoList = authInfoMapper.selectByUserId(CurrentUtil.getUserId());

        // 获取一级菜单
        menus = authInfoList.stream()
                .filter(item -> item.getParentId() == 0)
                .map(item -> {
                    // 递归查询子菜单
                    findChildren(item, authInfoList);
                    return item;
                })
                .collect(Collectors.toList());

        // 将菜单存入redis
        redisTemplate.opsForValue().set(UserConstant.MENU_PREFIX + CurrentUtil.getUserId(), menus, UserConstant.MENU_EXPIRE, UserConstant.MENU_EXPIRE_UNIT);

        return menus;
    }

    @Override
    public List<AuthInfo> getAuthTree() {
        List<AuthInfo> authInfoList = this.list();

        List<AuthInfo> list = authInfoList.stream()
                .filter(item -> item.getParentId() == 0)
                .map(item -> {
                    // 递归查询子权限
                    findChildren(item, authInfoList);
                    return item;
                })
                .collect(Collectors.toList());

        return list;
    }

    @Override
    public AuthInfo findByAuthName(String authName) {
        return this.getOne(new LambdaQueryWrapper<AuthInfo>().eq(AuthInfo::getAuthName, authName));
    }

    @Override
    public AuthInfo findByAuthUrl(String authUrl) {
        return this.getOne(new LambdaQueryWrapper<AuthInfo>().eq(AuthInfo::getAuthUrl, authUrl));
    }

    @Override
    public AuthInfo findByAuthCode(String authCode) {
        return this.getOne(new LambdaQueryWrapper<AuthInfo>().eq(AuthInfo::getAuthCode, authCode));
    }

    @Override
    public void add(AuthInfo authInfo) {
        // 权限状态默认为启用
        authInfo.setAuthState(CommonConstant.AUTH_STATE_ENABLE);
        this.save(authInfo);
    }

    @Override
    public void authEnable(Integer id) {
        AuthInfo authInfo = new AuthInfo();
        authInfo.setAuthId(id);
        authInfo.setAuthState(CommonConstant.AUTH_STATE_ENABLE);
        this.updateById(authInfo);
    }

    @Override
    public void authDisable(Integer id) {
        AuthInfo authInfo = new AuthInfo();
        authInfo.setAuthId(id);
        authInfo.setAuthState(CommonConstant.AUTH_STATE_DISABLE);
        this.updateById(authInfo);
    }

    @Override
    public void authDelete(Integer id) {
        /**
         * 判断权限是否关联角色
         */
        boolean exists = roleAuthMapper.exists(new LambdaQueryWrapper<RoleAuth>().eq(RoleAuth::getAuthId, id));
        if(exists){
            throw new RuntimeException("该权限已被角色关联，无法删除！");
        }

        /**
         * 查找当前权限及所有子权限
         */
        List<Integer> deleteIds = new ArrayList<>();
        deleteIds.add(id);
        // 递归查询子权限的id
        findChildIds(id, deleteIds);

        /**
         * 批量删除权限
         */
        this.removeByIds(deleteIds);

        /**
         * 删除Redis中缓存的所有用户菜单
         */
        redisTemplate.delete(redisTemplate.keys(UserConstant.MENU_PREFIX + "*"));
    }

    /**
     * 递归查询子菜单
     */
    private void findChildren(AuthInfo item, List<AuthInfo> authInfoList) {
        List<AuthInfo> children = authInfoList.stream()
                .filter(subItem -> subItem.getParentId().equals(item.getAuthId()))
                .map(subItem -> {
                    findChildren(subItem, authInfoList);
                    return subItem;
                }).collect(Collectors.toList());
        item.setChildAuth(children);
    }

    /**
     * 递归查询子权限的id
     */
    private void findChildIds(Integer id, List<Integer> deleteIds) {
        List<AuthInfo> authInfoList = this.list(new LambdaQueryWrapper<AuthInfo>().eq(AuthInfo::getParentId, id));
        if (!CollectionUtils.isEmpty(authInfoList)){
            authInfoList.forEach(item -> {
                deleteIds.add(item.getAuthId());
                findChildIds(item.getAuthId(), deleteIds);
            });
        }
    }
}




